package com.winit.feature.manager;

import com.winit.common.base.bean.ExecuteResult;
import com.winit.commons.util.ObjectToString;
import com.winit.feature.model.Feature;
import com.winit.indexing.service.IIdexingService;
import com.winit.menu.model.MatrixMenu;
import com.winit.menu.repository.MatrixMenuRepository;
import com.winit.page.model.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class PathContainer implements ApplicationListener<ContextRefreshedEvent> {
    private static Logger logger = LoggerFactory.getLogger(PathContainer.class);

    private static final class NodeInfo {
        private String name;
        private String parentId;
        private List<String> childs;

        public NodeInfo(String name, String parentId) {
            this.name = name;
            this.parentId = parentId;
        }

        public NodeInfo(String name, String parentId, List<String> childs) {
            this.name = name;
            this.parentId = parentId;
            if (null == childs) {
                childs = new ArrayList<>();
            }
            this.childs = childs;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getParentId() {
            return parentId;
        }

        public void setParentId(String parentId) {
            this.parentId = parentId;
        }

        public List<String> getChilds() {
            return childs;
        }

        public void setChilds(List<String> childs) {
            this.childs = childs;
        }
    }

    private volatile boolean init = false;

    private volatile Map<String, NodeInfo> container = null;

    @Autowired
    private FeatureManager featureManager;
    @Autowired
    private IIdexingService indexingService;
    @Autowired
    MatrixMenuRepository menuRepository;


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            this.init();
        }
    }

    private synchronized void init() {
        if (init) {
            return;
        }
        container = new ConcurrentHashMap<>();
        //找到所有系统
        List<MatrixMenu> list = menuRepository.findByParentId("0");
        for (MatrixMenu sys:list){
            initBySystem(sys.getSys());
        }
        init = true;
    }

    private void initBySystem(String sys) {
        ExecuteResult executeResult = featureManager.getAllElements(sys, false);
        Map<String, Object> data = (Map<String, Object>) executeResult.getData();
        List<MatrixMenu> menus = (List<MatrixMenu>) data.get("menus");
        List<Page> pages = (List<Page>) data.get("pages");
        List<Feature> features = (List<Feature>) data.get("features");
        if (!CollectionUtils.isEmpty(menus)) {
            for (MatrixMenu menu : menus) {
                logger.info("com.winit.feature.manager.PathContainer.initBySystem " + ObjectToString.getString(menu));
                container.put(menu.getId(), new NodeInfo(menu.getMenu_name(), menu.getParent_id(), null == menu.getChildren() ? new ArrayList<String>() : menu.getChildren()));
            }
        }
        if (!CollectionUtils.isEmpty(pages)) {
            for (Page page : pages) {
                logger.info("com.winit.feature.manager.PathContainer.initBySystem " + ObjectToString.getString(page));
                container.put(page.getId(), new NodeInfo(page.getTitle(), page.getMenuId(), null == page.getChildren() ? new ArrayList<String>() : page.getChildren()));
            }
        }
        if (!CollectionUtils.isEmpty(features)) {
            for (Feature feature : features) {
                logger.info("com.winit.feature.manager.PathContainer.initBySystem " + ObjectToString.getString(feature));
                container.put(feature.getId(), new NodeInfo(feature.getFeatureName(), feature.getOriginalPageId()));
            }
        }
    }

    public void updatePath(String id, String parentId, String name, List<String> childs) {
        if (!init) {
            this.init();
        }
        this.container.put(id, new NodeInfo(name, parentId, childs));
    }

    public void add(String id, String parentId, String name, List<String> childs) {
        if (!init) {
            this.init();
        }
        this.container.put(id, new NodeInfo(name, parentId, childs));
    }


    public void remove(String id) {
        if (!init) {
            this.init();
        }
        this.container.remove(id);
    }

    public String getPathById(String id) {
        return this.getPathById(id, true);
    }

    public String getPathById(String id, boolean withSelf) {
        if (!init) {
            this.init();
        }
        return this.getPath(id, "", withSelf);
    }

    private String getPath(String id, String path, boolean withSelf) {
        NodeInfo nodeInfo = this.container.get(id);
        if (null == nodeInfo) {
            return path;
        }
        String parentId = nodeInfo.getParentId();
        if ((!StringUtils.isEmpty(parentId)) && (!"-1".equals(parentId)) && (!"0".equals(parentId))) {
            if (withSelf) {
                path = "/" + nodeInfo.getName() + path;
            }
            return this.getPath(parentId, path, true);
        }
        return path;
    }

    public void refreshFromDb() {
        this.init = false;
        this.init();
    }

    public List<String> getChild(String id) {
        if (StringUtils.isEmpty(id)) {
            return new ArrayList<>();
        }
        NodeInfo nodeInfo = this.container.get(id);
        if (null == nodeInfo) {
            return new ArrayList<>();
        }
        return nodeInfo.getChilds();
    }

    public NodeInfo getNodeInfo(String id) {
        NodeInfo nodeInfo = this.container.get(id);
        if (null == nodeInfo) {
            return null;
        }
        return nodeInfo;
    }
}
